package com.pz.cloud.framework.workflow.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pz.cloud.framework.base.model.WorkflowEntity;
import com.pz.cloud.framework.business.workflow.entity.ProcessBind;
import com.pz.cloud.framework.business.workflow.entity.ProcessBindRule;
import com.pz.cloud.framework.business.workflow.service.IProcessBindRuleService;
import com.pz.cloud.framework.business.workflow.service.IProcessBindService;
import com.pz.cloud.framework.util.FieldUtil;
import com.pz.cloud.framework.workflow.mapper.ProcessBindMapper;
import lombok.val;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 工作流服务
 * @author mazezhan
 */
@Transactional(rollbackFor = Exception.class)
@Service
public class ProcessBindServiceImpl extends ServiceImpl<ProcessBindMapper, ProcessBind> implements IProcessBindService {
    @Autowired
    private IProcessBindRuleService processBindRuleService;

    @Override
    public boolean save(ProcessBind entity) {
        boolean b;
        if (StringUtils.isEmpty(entity.getId())) {
             b = super.save(entity);
        }else{
             b = super.updateById(entity);
        }

        List<ProcessBindRule> ruleList = entity.getRuleList();
        if(!CollectionUtils.isEmpty(ruleList)){
            for (ProcessBindRule processBindRule : ruleList) {
                processBindRule.setProcessBindId(entity.getId());
            }
        }
        processBindRuleService.saveOrUpdateBatch(ruleList);
        return b;
    }

    @Override
    public ProcessBind getById(Serializable id) {
        ProcessBind processBind = super.getById(id);
        if(processBind!=null){
            List<ProcessBindRule> ruleList = processBindRuleService.findByProcessBindId(processBind.getId());
            processBind.setRuleList(ruleList);
        }
        return processBind;
    }

    @Override
    public ProcessBind findByProcessKey(String processKey) {
        QueryWrapper<ProcessBind> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("processKey",processKey);
        List<ProcessBind> list = this.list(queryWrapper);
        if(!CollectionUtils.isEmpty(list)){
            return list.get(0);
        }
        return null;
    }
    @Override
    public List<ProcessBind> findByRelatedTable(String tableName) {
        LambdaQueryWrapper<ProcessBind> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ProcessBind::getRelatedTable,tableName);
        List<ProcessBind> list = this.list(queryWrapper);
        return list;
    }

    @Override
    public ProcessBind findProcessBind(WorkflowEntity workflowEntity) {
        String tableName = workflowEntity.getTableName();
        if(StringUtils.isNotEmpty(tableName)){
            LambdaQueryWrapper<ProcessBind> query = new LambdaQueryWrapper<>();
            query.eq(ProcessBind::getRelatedTable,tableName);
            query.orderByAsc(ProcessBind::getPriority);
            List<ProcessBind> list = this.list(query);
            if(!CollectionUtils.isEmpty(list)){
                for (ProcessBind processBind : list) {
                    if(matchProcess(workflowEntity,processBind)){
                        return processBind;
                    }
                }
            }
        }
        return null;
    }

    @Override
    public boolean removeById(Serializable id) {
        boolean b = super.removeById(id);
        List<ProcessBindRule> ruleList = processBindRuleService.findByProcessBindId(id.toString());
        if(!CollectionUtils.isEmpty(ruleList)){
            processBindRuleService.removeByIds(ruleList.stream().map(ProcessBindRule::getId).collect(Collectors.toList()));
        }
        return b;
    }

    @Override
    public boolean removeByIds(Collection<? extends Serializable> idList) {
        for (Serializable id : idList) {
            removeById(id);
        }
        return true;
    }

    /**
     * 流程规则匹配
     * @param workflowEntity
     * @param processBind
     * @return
     */
    private boolean matchProcess(WorkflowEntity workflowEntity,ProcessBind processBind ){
        boolean match = true;
        List<ProcessBindRule> processBindRules = processBindRuleService.findByProcessBindId(processBind.getId());
        if(!CollectionUtils.isEmpty(processBindRules)){
            outside:for (ProcessBindRule processBindRule : processBindRules) {
                String ruleFiledName = processBindRule.getRuleFiledName();
                String ruleFieldValue = processBindRule.getRuleFieldValue();
                String express = processBindRule.getExpress();
                Object filedValue = FieldUtil.getFieldValueByName(workflowEntity, ruleFiledName);

                switch (express){
                    case ">":{
                        //是否符合条件
                        if(new BigDecimal(filedValue.toString()).compareTo(new BigDecimal(ruleFieldValue))<0){
                            match = false;
                            break outside;
                        }
                        break ;
                    }
                    case "<":{
                        //是否符合条件
                        if(new BigDecimal(filedValue.toString()).compareTo(new BigDecimal(ruleFieldValue))>0){
                            match = false;
                            break outside;
                        }
                        break ;
                    }
                    case "eq":{
                        if(filedValue instanceof String){
                            if(!filedValue.equals(ruleFieldValue)){
                                match = false;
                                break outside;
                            }
                        }else if(filedValue instanceof Number){
                            if(new BigDecimal(filedValue.toString()).compareTo(new BigDecimal(ruleFieldValue))!=0){
                                match = false;
                                break outside;
                            }
                        }else{
                            match = false;
                            break outside;
                        }
                        break;
                    }
                    case "like":{
                        if(!filedValue.toString().contains(ruleFieldValue)){
                            match = false;
                            break outside;
                        }
                        break;
                    }
                }
            }
        }
        return  match;

    }

}
